﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UMLTouch.Core.Entities;
using System.Windows;

namespace UMLTouch.DomainRecognition.SegmentationAlgorithms
{
    public class PersonnalAlgorithm : ISegmentationAlgorithm
    {
        #region ISegmentationAlgorithm Members

        double _angleThreshold;
     
        public PersonnalAlgorithm(double angleThreshold)
        {
            _angleThreshold = angleThreshold;
            
        }

        public PersonnalAlgorithm()
            : this(30)
        {

        }

        private Stroke FilterStroke(Stroke s)
        {
            Boolean changed = false;
            

            do
            {
                changed = false;
                Point p0, p1, p2, p3;
                Vector v0, v1, v2;

                for (int nextI = 2; nextI < s.Count; nextI++)
                {
                    p0 = s[nextI - 2];
                    p1 = s[nextI - 1];
                    p2 = s[nextI];

                    if (nextI + 1 < s.Count)
                        p3 = s[nextI + 1];
                    else
                        p3 = s.First();


                    v0 = new Vector(p0.X - p1.X, p0.Y - p1.Y);
                    v1 = new Vector(p2.X - p1.X, p2.Y - p1.Y);
                    v2 = new Vector(p3.X - p1.X, p3.Y - p1.Y);

                    double theta0 = Math.Abs(Vector.AngleBetween(v0, v1));
                    double theta1 = Math.Abs(Vector.AngleBetween(v0, v1));

                    double projectedVariation = Math.Abs(theta1 - theta0);


                    if (v0.Length < s.PointDistanceAvg * 20 / 100)
                    {
                        s.Remove(p1);
                        changed = true;
                    }
                    else
                    {
                        if (projectedVariation <= _angleThreshold)
                        {
                            if (0 <= theta0 && theta0 <= 15)
                            {
                                s.Remove(p0);
                                changed = true;

                            }
                            else
                                if (180 - _angleThreshold <= theta0 && theta0 <= 180)
                                {
                                    s.Remove(p1);
                                    changed = true;
                                }
                        }
                    }
                }


                if (!changed && !s.IsClosed)
                {
                    if (s.DistanceFirstToLast() < s.PointDistanceAvg * 50 / 100)
                    {
                        s[0] = s.Last();
                        s.Insert(0, s.Last());
                        changed = true;
                        s.IsClosed = true;
                    }
                }                

            } while (changed);

            return s;
        }


        public SegmentedStroke SegmentStroke(Stroke s)
        {

            SegmentedStroke ret = new SegmentedStroke(s);
            //List<Segment> ret = new List<Segment>();

            Stroke cleanedStroke = FilterStroke(s);

            Boolean firstLoop = true;
            Point pred = new Point();

            foreach (Point p in s)
            {
                if (firstLoop)
                {
                    pred = p;
                    firstLoop = false;
                }
                else //if((pred - p).Length > 10 * s.Length /100)
                {
                    Segment newSeg = new Segment(s,pred, p);  
                    if(newSeg.Length >20)            
                    {   
                        ret.Segments.Add(newSeg);
                        pred = p;

                    }
                }
                
            }


            //segmentedStroke.Segments = ret;
            return ret;       
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
          
        }

        #endregion
    }
}
